package com.sunhy.accountserver.service.impl;

import com.alipay.sofa.runtime.api.annotation.SofaService;
import com.sunhy.accountserver.entity.BillEntity;
import com.sunhy.accountserver.facade.BillService;
import com.sunhy.accountserver.mapper.AccountMapper;
import com.sunhy.accountserver.mapper.BillMapper;
import com.sunhy.accountserver.mapper.BillToMapper;
import com.sunhy.accountserver.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

@Slf4j
@Service
@SofaService
public class BillServiceImpl implements BillService {

    @Autowired
    private BillMapper billMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private BillToMapper billToMapper;

    @Override
    public String message() {
        return "哈哈Bill：" + DateUtil.getDatetimeStr(new Date());
    }

    /**
     * 发起一个转账请求
     * 创建出Bill记录，但其状态为0，返回Bill的Id
     * @param fromUserId 发起人的userId
     * @param toUserId 接收人的userId
     * @param amount 转账金额
     * @return
     */
    @ShardingTransactionType(TransactionType.XA)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long initiateTransfer(Integer fromUserId, Integer toUserId, String amount) {
        // 创建正向的Bill实体类 其中id自增长
        // TODO 有问题啊 用雪花id
        BillEntity bill = new BillEntity();
        bill.setUserId(fromUserId);
        bill.setFromUserId(fromUserId);
        bill.setToUserId(toUserId);
        bill.setAmount(new BigDecimal(amount));
        bill.setCreateDate(new Date());
        bill.setStatus(0);
        // 插入数据库
        billMapper.insert(bill);
        // 生成的 Bill Id
        Long primaryKey = bill.getId();

       // 生成反向的 BillTo实体类 插入toUser所在的数据库 主键非自增
        BillEntity billTo = new BillEntity();
        billTo.setId(primaryKey);
        billTo.setUserId(toUserId);
        billTo.setFromUserId(fromUserId);
        billTo.setToUserId(toUserId);
        billTo.setAmount(new BigDecimal(amount));
        billTo.setCreateDate(new Date());
        billTo.setStatus(0);
        // 反向的BillTo插入数据库
        billToMapper.insert(billTo);

        log.error("生成交易号：用户{} 向 用户{} 金额{}, 交易号：{}", fromUserId, toUserId, amount, primaryKey);

        return primaryKey;
    }

    /**
     * 确认执行转账
     * 执行用户账户金额扣减与增加的业务逻辑
     * @param billId 转账的账单Id
     */
    @ShardingTransactionType(TransactionType.XA)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String confirmTransfer(Long billId) {
        // 1. 先查询该bill的状态码 若bill的状态已经是200, 那么返回失败
        BillEntity bill = billMapper.selectById(billId);
        if (bill.getStatus() == 200) {
            return "转账已完成，无需重复操作！";
        }

        // 2.FromUser扣除转账金额并修改Bill的状态  (确保在同一个库中, 放在一个事务里)
        int a1 = accountMapper.updateSubAmountAndStatus(bill.getFromUserId(), bill.getAmount());
        int a2 = billMapper.updateStatusById(100, billId);

        // 3.ToUser添加转账金额 修改BillTo的状态
        int b1 = accountMapper.updateAddAmountAndStatus(bill.getToUserId(), bill.getAmount());
        int b2 = billToMapper.updateStatusById(100, billId);

        // 4. （c操作可能存在分布式事务的问题）
        int c = billMapper.updateStatusById(200, billId);

        // TODO 日志记录成功...

        return "SUCCESS";
    }

}
